﻿using System;
using System.Collections.Generic;
using System.Linq;
using RenRen.Schema;
using RenRen.Session;
using RenRen.Utility;
using RenRen.Common;

namespace RenRen.Rest {
    /// <summary>
    /// RenRen 好友接口 
    /// </summary>
    public class Friends : RestBase {
        #region Private Members

        private readonly Users _users;

        #endregion Private Members


        #region Constructor

        /// <summary>
        /// 
        /// </summary>
        /// <param name="users"></param>
        public Friends(Users users, RenRenSession session)
            : base(session) {
            _users = users;
        }

        #endregion Constructor


        #region 同步方法

        /// <summary>
        /// 判断两组用户是否互为好友关系，比较的两组用户数必须相等。 
        /// </summary>
        /// <param name="uids1">第一组用户</param>
        /// <param name="uids2">第二组用户</param>
        /// <returns>返回friend_info集合<are_friends>是否为好友，1表示是，0表示否</returns>
        public IList<friend_info> AreFriends(List<user> uids1, List<user> uids2) {
            var u1 = (from u in uids1 select u.uid).ToList();
            var u2 = (from u in uids2 select u.uid).ToList();
            return AreFriends(u1, u2);
        }

        /// <summary>
        /// 判断两个用户是否互为好友关系 
        /// </summary>
        /// <param name="user1">用户甲</param>
        /// <param name="user2">用户乙</param>
        /// <returns>返回friend_info集合<are_friends>是否为好友，1表示是，0表示否</returns>
        public IList<friend_info> AreFriends(user user1, user user2) {
            var uids1 = new List<int>();
            var uids2 = new List<int>();
            uids1.Add(user1.uid);
            uids2.Add(user2.uid);
            return AreFriends(uids1, uids2);
        }

        /// <summary>
        /// 判断两个用户是否互为好友关系 
        /// </summary>
        /// <param name="uid1">用户甲ID</param>
        /// <param name="uid2">用户乙ID</param>
        /// <returns>返回friend_info集合<are_friends>是否为好友，1表示是，0表示否</returns>
        public IList<friend_info> AreFriends(int uid1, int uid2) {
            var uids1 = new List<int>();
            var uids2 = new List<int>();
            uids1.Add(uid1);
            uids2.Add(uid2);
            return AreFriends(uids1, uids2);
        }

        /// <summary>
        /// 判断两个用户是否互为好友关系 
        /// </summary>
        /// <param name="uids1">第一组用户ids.</param>
        /// <param name="uids2">第二组用户ids</param>
        /// <returns>返回friend_info集合<are_friends>是否为好友，1表示是，0表示否</returns>
        public IList<friend_info> AreFriends(List<int> uids1, List<int> uids2) {
            return AreFriends(uids1, uids2, false, null, null);
        }

        /// <summary>
        /// 得到当前登录用户的好友列表，得到的只是含有好友uid的列表
        /// </summary>
        /// <returns>好友ID集合</returns>
        /// <remarks></remarks>
        public IList<int> Get() {
            return Get(0);
        }

        /// <summary>
        /// 得到当前用户的好友列表，得到的只是含有好友uid的列表
        /// </summary>
        /// <param name="uid">对应的用户ID</param>
        /// <returns>好友ID集合</returns>
        /// <remarks></remarks>
        public IList<int> Get(int uid) {
            return Get(uid, false, null, null);
        }

        /// <summary>
        /// 返回已经添加了一个应用的好友的用户Id列表，此接口只返回全部好友中的数据
        /// </summary>
        /// <returns>返回已经添加了一个应用的好友的用户Id列表</returns>
        /// <remarks>此接口只返回全部好友中的数据，如果你需要完整的全部数据请调用Friends.getAppFriends。 </remarks>
        public IList<int> GetAppUsers() {
            return GetAppUsers(false, null, null);
        }

        /// <summary>
        /// 得到当前登录用户的好友列表
        /// </summary>
        /// <returns>返回好友基本信息对象集合</returns>
        public IList<friend> GetFriends() {
            return GetFriends(0);
        }


        /// <summary>
        /// 得到当前用户的好友列表
        /// </summary>
        /// <param name="uid">对应的用户ID</param>
        public IList<friend> GetFriends(int uid) {
            return GetFriends(uid, false, null, null);
        }

        /// <summary>
        /// 返回App好友的ID列表。App好友是指某个用户安装了同一应用的好友。
        /// </summary>
        /// <returns></returns>
        /// <remarks>这个接口与friends.getAppUsers异同如下：
        /// 相同点
        ///
        /// 1. 都是取App好友的接口；
        /// 2. 返回值的格式相同；
        /// 3. 存在缓存数据，最大有一个小时的延迟。 
        ///
        /// 不同点
        ///
        ///  1. friends.getAppFriends在调用的时候可以返回更多的用户信息，例如姓名，头像等，这样能减少多次调用 
        ///  </remarks>
        public IList<friend> GetAppFriends() {
            return GetAppFriends(false, null, null);
        }

        #endregion Synchronous Methods

        #region 异步方法

        /// <summary>
        /// 异步判断两组用户是否互为好友关系，比较的两组用户数必须相等。 
        /// </summary>
        /// <param name="uids1">第一组用户ids</param>
        /// <param name="uids2">第二组用户ids</param>
        /// <param name="callback">异步回调代理</param>
        /// <param name="state">异步调用状态对象</param>        
        /// <returns>是否是好友列表</returns>
        public void AreFriendsAsync(List<user> uids1, List<user> uids2, AreFriendsCallback callback, Object state) {
            var u1 = (from u in uids1 select u.uid).ToList();
            var u2 = (from u in uids2 select u.uid).ToList();
            AreFriendsAsync(u1, u2, callback, state);
        }

        /// <summary>
        ///  异步判断两组用户是否互为好友关系
        /// </summary>
        /// <param name="user1">用户甲</param>
        /// <param name="user2">用户乙</param>
        /// <param name="callback">异步回调代理</param>
        /// <param name="state">异步调用状态对象</param>        
        /// <returns>是否是好友列表</returns>
        public void AreFriendsAsync(user user1, user user2, AreFriendsCallback callback, Object state) {
            var u1 = new List<int>();
            var u2 = new List<int>();
            u1.Add(user1.uid);
            u2.Add(user2.uid);
            AreFriendsAsync(u1, u2, callback, state);
        }

        /// <summary>
        ///  异步判断两组用户是否互为好友关系
        /// </summary>
        /// <param name="uid1">用户甲</param>
        /// <param name="uid2">用户乙</param>
        /// <param name="callback">异步回调代理</param>
        /// <param name="state">异步调用状态对象</param>        
        /// <returns>是否是好友列表</returns>
        /// <remarks>The first array specifies one half of each pair, the second array the other half; therefore, they must be of equal size.</remarks>
        public void AreFriendsAsync(int uid1, int uid2, AreFriendsCallback callback, Object state) {
            var u1 = new List<int>();
            var u2 = new List<int>();
            u1.Add(uid1);
            u2.Add(uid2);
            AreFriendsAsync(u1, u2, callback, state);
        }

        /// <summary>
        ///  异步判断两组用户是否互为好友关系
        /// </summary>
        /// <param name="uids1">第一组用户ids</param>
        /// <param name="uids2">第二组用户ids</param>
        /// <param name="callback">异步回调代理</param>
        /// <param name="state">异步调用状态对象</param>        
        public void AreFriendsAsync(List<int> uids1, List<int> uids2, AreFriendsCallback callback, Object state) {
            AreFriends(uids1, uids2, true, callback, state);
        }

        /// <summary>
        /// 得到当前登录用户的好友列表，得到的只是含有好友uid的列表
        /// </summary>
        /// <param name="callback">异步回调代理</param>
        /// <param name="state">异步调用状态对象</param>        
          public void GetAsync(GetFriendsCallback callback, Object state) {
            GetAsync(0, callback, state);
        }

        /// <summary>
          /// 得到当前登录用户的好友列表，得到的只是含有好友uid的列表
        /// </summary>
          /// <param name="uid">当前用户</param>
          /// <param name="callback">异步回调代理</param>
          /// <param name="state">异步调用状态对象</param>        
        public void GetAsync(int uid, GetFriendsCallback callback, Object state) {
            Get(uid, true, callback, state);
        }

        /// <summary>
        /// 返回已经添加了一个应用的好友的用户Id列表，此接口只返回全部好友中的数据
        /// </summary>
        /// <param name="callback">异步回调代理</param>
        /// <param name="state">异步调用状态对象</param>        
        public void GetAppUsersAsync(GetAppUsersCallback callback, Object state) {
            GetAppUsers(true, callback, state);
        }

        /// <summary>
        /// 返回已经添加了一个应用的好友的用户Id列表，此接口只返回全部好友中的数据
        /// </summary>
        /// <param name="callback">异步回调代理</param>
        /// <param name="state">异步调用状态对象</param>      
        public void GetAppFriendsAsync(Users.GetInfoCallback callback, Object state) {
            GetAppFriends(true, callback, state);
        }

        /// <summary>
        /// 得到当前用户的好友列表
        /// </summary>
        /// <param name="callback">异步回调代理</param>
        /// <param name="state">异步调用状态对象</param>        
        public void GetFriendsAsync(Users.GetInfoCallback callback, Object state) {
            GetFriendsAsync(-1, callback, state);
        }


        /// <summary>
        /// 得到当前用户的好友列表
        /// </summary>
        /// <param name="callback">异步回调代理</param>
        /// <param name="state">异步调用状态对象</param>        
        public void GetFriendsAsync(int uid, Users.GetInfoCallback callback, Object state) {
            GetFriends(uid, true, callback, state);
        }

        #endregion Asynchronous Methods



        #region 私有方法

        private IList<friend_info> AreFriends(List<int> uids1, List<int> uids2, bool isAsync, AreFriendsCallback callback, Object state) {
            var parameterList = new Dictionary<string, string>
			                    	{
			                    		{"method", "xiaonei.friends.areFriends"}
			                    	};
            Utilities.AddList(parameterList, "uids1", uids1);
            Utilities.AddList(parameterList, "uids2", uids2);

            if (isAsync) {
                SendRequestAsync<friends_areFriends_response, IList<friend_info>>(parameterList, new RenRenCallCompleted<IList<friend_info>>(callback), state, "friend_info");
                return null;
            }

            var response = SendRequest<friends_areFriends_response>(parameterList);
            return response == null ? null : response.friend_info;
        }

        private IList<int> Get(int uid, bool isAsync, GetFriendsCallback callback, Object state) {
            var parameterList = new Dictionary<string, string> { { "method", "xiaonei.friends.get" } };
            Utilities.AddOptionalParameter(parameterList, "uid", uid);

            if (isAsync) {
                SendRequestAsync<friends_get_response, IList<int>>(parameterList,HasSession, new RenRenCallCompleted<IList<int>>(callback), state, "uid");
                return null;
            }

            var response = SendRequest<friends_get_response>(parameterList,HasSession);
            return response == null ? null : response.uid;
        }

        private IList<int> GetAppUsers(bool isAsync, GetAppUsersCallback callback, Object state) {
            var parameterList = new Dictionary<string, string> { { "method", "xiaonei.friends.getAppUsers" } };

            if (isAsync) {
                SendRequestAsync<friends_getAppUsers_response, IList<int>>(parameterList, new RenRenCallCompleted<IList<int>>(callback), state, "uid");
                return null;
            }

            var response = SendRequest<friends_getAppUsers_response>(parameterList);
            return response == null ? null : response.uid;
        }

        private IList<friend> GetAppFriends(bool isAsync, Users.GetInfoCallback callback, Object state) {
            var parameterList = new Dictionary<string, string> { { "method", "xiaonei.friends.getAppFriends" } };
            if (Batch.IsActive) {
                throw new Exception("Extended API methods are not supported within a batch");
            }

            if (isAsync) {
                SendRequestAsync<friends_getAppFriends_response, IList<int>>(parameterList, (friends, state2, e) => OnGetFriendsCompleted(friends, callback, state2, e), state, "uid");
                return null;
            }

            var response = SendRequest<friends_getAppFriends_response>(parameterList);


            return response == null ? null : response.friend;
        }

        private IList<friend> GetFriends(int uid, bool isAsync, Users.GetInfoCallback callback, Object state) {
            if (Batch.IsActive) {
                throw new Exception("Extended API methods are not supported within a batch");
            }

            var parameterList = new Dictionary<string, string> { { "method", "xiaonei.friends.getFriends" } };
            Utilities.AddOptionalParameter(parameterList, "uid", uid);

            if (isAsync) {
                SendRequestAsync<friends_getFriends_response, IList<int>>(parameterList, (friends, state2, e) => OnGetFriendsCompleted(friends, callback, state2, e), state, "uid");
                return null;
            }

            var response = SendRequest<friends_getFriends_response>(parameterList,HasSession);
            if (response == null) return null;

            return response.friend;
        }

        private void OnGetFriendsCompleted(IList<int> friends, Users.GetInfoCallback callback, Object state, RenRenException e) {
            _users.GetInfoAsync(friends.AsString(), callback, state);
        }

        private void OnGetAppUsersForObjectsCompleted(IList<int> users, Object state, RenRenException e) {
            Object[] stateObjects = (Object[])state;
            var callback = (Users.GetInfoCallback)stateObjects[0];
            var originalState = stateObjects[1];
            _users.GetInfoAsync(callback, originalState);
        }

        #endregion Private Methods

        #region 代理

        /// <summary>
        /// AreFriends调用完成代理
        /// </summary>
        /// <param name="friendInfo">friend_info集合</param>
        /// <param name="state">异步请求状态</param>
        /// <param name="e">异常对象</param>
        public delegate void AreFriendsCallback(IList<friend_info> friendInfo, Object state, RenRenException e);

        /// <summary>
        /// GetFriends调用完成代理
        /// </summary>
        /// <param name="friends">好友ID集合</param>
        /// <param name="state">异步请求状态</param>
        /// <param name="e">异常对象</param>
        public delegate void GetFriendsCallback(IList<int> friends, Object state, RenRenException e);
        /// <summary>
        /// GetAppUsers 调用完成代理
        /// </summary>
        /// <param name="users">用户ID列表</param>
        /// <param name="state">异步请求状态</param>
        /// <param name="e">异常对象</param>
        public delegate void GetAppUsersCallback(IList<int> users, Object state, RenRenException e);
        /// <summary>
        /// GetUserObjects调用完成代理
        /// </summary>
        /// <param name="users">用户ID列表</param>
        /// <param name="state">异步请求状态t</param>
        /// <param name="e">异常对象</param>
        public delegate void GetUserObjectsCallback(IList<user> users, Object state, RenRenException e);

        #endregion Delegates
    }
}